import 'dart:convert';
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:path_provider/path_provider.dart';
import 'package:share_fit/app/helper/storage_mixin.dart';
import 'package:share_fit/app/tools/app_util.dart';
import 'package:share_fit/app/tools/log_utils.dart';
import 'package:share_fit/app/ute/uteped_const.dart';
import 'package:share_fit/app/ute/uteped_device.dart';
import 'package:crypto/crypto.dart';

class UpgradeHelper with StorageMixin {

  // static const upgradeUrl = "https://apphtml.wiodo.tech/watch_fireware/index.json";
  // static const upgradeUrl = "http://192.168.3.137:8086/files/watch_upgrade.json";
  static const upgradeUrl = "https://watchapp.wiodo.tech/firmware/watch_upgrade.json";
  static const checkUpgradeTime = "checkUpgradeTime";

  static UpgradeHelper instance = UpgradeHelper._();

  UpgradeHelper._();

  void init() {
    initStorage();
    remove(UTEPedConst.keyUpgradable);
    remove(UTEPedConst.keyUpgradeInfo);
    remove(UTEPedConst.keyUpgradeDialogShow);
  }

  Future<void> checkUpdateWithTime() async {
    final now = DateTime.now();
    var checkTime = read(checkUpgradeTime, defaultValue: 0);
    var interval = now.millisecondsSinceEpoch - checkTime;
    if (interval < 10 * 60 * 1000) {
      logger.d("already checked ...");
      return;
    }

    checkUpdate();
    save(checkUpgradeTime, now.millisecondsSinceEpoch);
  }

  Future<void> checkUpdate() async {
    logger.d("check update...");
    if (read(UTEPedConst.keyUpgradable, defaultValue: false)) {
      logger.d("already upgradable.");
      return;
    }

    // 更新版本信息
    await UTEPedDevice.instance.updateDeviceInfo();

    final dio = Dio();
    try {
      Response response = await dio.get(upgradeUrl);
      Map map = jsonDecode('$response');
      var deviceInfo = UTEPedDevice.instance.deviceInfo;
      for (var mapItem in map["watch_firmware"]) {
        var version = mapItem["version"];
        if (mapItem["model"] == deviceInfo.firmware && AppUtil.compareVersion(version, deviceInfo.versionName)) {
          await downloadFirmware(mapItem["url"], mapItem["MD5"], mapItem["model"]);
          save(UTEPedConst.keyUpgradeInfo, mapItem);
          break;
        }
      }
    } catch(e) {
      logger.d(e);
    }
  }

  /// 升级检测部分
  Future<void> downloadFirmware(String binUrl, String md5, String model) async {
    logger.d("downloadFirmware: $binUrl");
    try {
      var dir = await getApplicationDocumentsDirectory();
      var binFilePath = "${dir.path}/$model.bin";
      var binFile = File(binFilePath);
      if (binFile.existsSync()) {
        String fileMd5 = await getFileMd5(binFilePath);
        if (fileMd5 == md5) {
          save(UTEPedConst.keyUpgradable, true);
          save(UTEPedConst.keyUpgradeFilePath, binFilePath);
          return;
        }
        else {
          binFile.deleteSync();
        }
      }

      final dio = Dio();
      await dio.download(binUrl, binFilePath);
      String fileMd5 = await getFileMd5(binFilePath);
      if (fileMd5 == md5) {
        save(UTEPedConst.keyUpgradable, true);
        save(UTEPedConst.keyUpgradeFilePath, binFilePath);
      }
    } catch (e) {
      logger.d(e);
    }

    logger.d("downloadFirmware...end");
  }

  Future<String> getFileMd5(String filePath) async {
    File file = File(filePath);

    List<int> bytes = await file.readAsBytes();
    Digest md5Digest = md5.convert(bytes);

    return md5Digest.toString();
  }

  @override
  String getStoragePath() {
    return UTEPedConst.pathDevice;
  }
}